﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;

namespace GShare1._0.Client
{
    public delegate void ClientListUpdateDelegate(List<ClientInfo> clientList);
    public partial class GUI_Client : Form
    {
        UiThreadInvoker _invoker;
        MessageBoxInvoker mboxInvoker;
        MainThreadInvoker mainThreadInvoker;
        ClientListUpdateDelegate listInvoker;

        public AutoResetEvent autoReset = new AutoResetEvent(false);

        public GUI_Client()
        {
            InitializeComponent();
            _invoker = OfflineEvent;
            mboxInvoker = MessageDel;
            mainThreadInvoker = MainThreadDelegate;
            listInvoker = ListUpdater;

            Shown += GUI_Client_Shown;
            FormClosing += GUI_Client_FormClosing;
        }

        private void MainThreadDelegate(Delegate del)
        {
            this.BeginInvoke(del);
        }

        void GUI_Client_FormClosing(object sender, FormClosingEventArgs e)
        {
            autoReset = new AutoResetEvent(false);
        }

        void GUI_Client_Shown(object sender, EventArgs e)
        {
            this.autoReset.Set();
        }

        private void MessageDel(string msg)
        {
            MethodInvoker invoker = delegate
                {
                    textBox3.Text += msg + Environment.NewLine;
                };
            if (!Visible)
            {
                autoReset.WaitOne();
            }
            if (Visible)
            {
                BeginInvoke(invoker);
            }          
                
        }

        public ClientConnection Client;

        public void TryConnect(ClientConnection client)
        {
            try
            {
                //Set Delegates for UI
                client.MessageInvoker = mboxInvoker;
                client.Invoker = _invoker;
                client.MainThreadInvoker = mainThreadInvoker;
                client.ListInvoker = listInvoker;

                client.Connect();
                //autoReset.WaitOne(5000);
                //needs more specialized way of connecting...
                
                if (client.Connected == false)
                {
                    client.Socket.Dispose();
                    client.Socket.Close();
                    MessageBox.Show("Connection Failed");
                    Close();
                }
                else
                {
                    Client = client;
                    ShowDialog();
                    
                }
            }
            catch (Exception)
            {
                
                throw;
            }
        }

        private void button3_Click_1(object sender, EventArgs e)
        {
            if (Client != null)
            {
                if (Client.Download == null)
                {
                    BeginInvoke((MethodInvoker)delegate
                    {
                        Client.UploadFile();
                    });
                            
                }
                
            }
        }

        private void button2_Click_1(object sender, EventArgs e)
        {
            if (Client != null && !string.IsNullOrEmpty(textBox4.Text))
            {
                Client.SendMessage("TEXT",textBox4.Text);
                textBox4.Clear();
            }
        }

        private void OfflineEvent()
        {
            MethodInvoker invoker = new MethodInvoker(delegate
                {
                    this.Close();
                });
            //Form has no handle and cannot invoke on main thread yet 
            if (Visible)
            {
                BeginInvoke(invoker);
            }
            
        }

        private void textBox4_KeyPress(object sender, KeyPressEventArgs e)
        {
            // Boolean flag used to determine when a character other than a number is entered. 
            if ((Keys)e.KeyChar == Keys.Enter)
            {
                button2_Click_1(this, new EventArgs());
                textBox4.Refresh();
            }
            

        }

        private void ListUpdater(List<ClientInfo> clientInfoList)
        {
            MethodInvoker invoker = delegate
                {

                    listView1.Items.Clear();
                    if (clientInfoList.Count != 0)
                    {

                        foreach (ClientInfo client in clientInfoList.ToArray())
                        {
                            ListViewItem clientItem = new ListViewItem(client.UserName);
                            //clientItem.SubItems.Add(client._clientSocket.RemoteEndPoint.ToString());
                            //clientItem.SubItems.Add(client.AdminUser.ToString());
                            //clientItem.SubItems.Add(client.clientInfo.ConnectionTime.ToString());
                            clientItem.Tag = client;
                            listView1.Items.Add(clientItem);
                        }
                    }
                };
            BeginInvoke(invoker);
        }

        private void buttonSendPersonalMessage_Click(object sender, EventArgs e)
        {
            if (listView1.SelectedItems.Count != 0)
            {
                if (listView1.SelectedItems[0] != null)
                {

                    ClientInfo client = (ClientInfo)listView1.SelectedItems[0].Tag;
                    if(client.UserName != Client.Username)
                    {
                        Client.SendMessage("PRIVATE_MESSAGE", client.UserName + ',' + textBox4.Text);
                        MessageDel("*" + Client.Username + ": " + textBox4.Text);   
                    }
                    else
                    {
                        MessageBox.Show("Cannot Send Message To Self");
                    }
                    
                }
                
            }
        }
    }
}
